#include <stdio.h>
#include <fcntl.h>
#include <iostream>
#include <sys/types.h>
#include <FTSSException.hpp>
#include <errno.h>
#include <Util.hpp>
#include <string.h>
#include <stdlib.h>
#include <BPlusTree.hpp>
using namespace FTSS;
using namespace MAIL;
#define TEST_SIZE 1000
#define TREE_WIDTH 5
int main(int argc, char ** argv){
	if (argc < 2){
		fprintf(stderr, "usage : data_directory\n");
		return EX_USAGE;
	}
	try {
		fprintf(stdout, "BPlusNodesStorage ... ");
		BPlusTreeNodeStorage storage_nodes(DirFilePath(argv[1], "BNodesStorage.ftss").c_str(),
						   DirFilePath(argv[1], "BNodesWhiteSpace.ftss").c_str());
		fprintf(stdout, "OK\n");

		fprintf(stdout, "BPlusLeafStorage ... ");
		BPlusTreeLeafsStorage storage_leafs(DirFilePath(argv[1], "BLeafsStorage.ftss").c_str(), 
						    DirFilePath(argv[1], "BLeafsWhiteSpace.ftss").c_str());
		fprintf(stdout, "OK\n" );
		fprintf(stdout, "BPlusTree ...\n");

/*		BPlusNode<BPlusTreeNodeData, TREE_WIDTH> * nod_tmp = new BPlusNode<BPlusTreeNodeData, TREE_WIDTH>();
		fprintf(stderr, "stored_node_id=%d\n", storage_nodes.DumpNode(nod_tmp));
		BPlusNode<BPlusTreeNodeData, TREE_WIDTH> * nod_tmp1 = storage_nodes.GetNodeById<BPlusTreeNodeData, TREE_WIDTH>(1);
		fprintf(stderr, "get_node_id=%lld\n",nod_tmp1->id );
		delete nod_tmp;*/

		BPlusLeaf<BPlusTreeNodeData, BPlusTreeLeafData, TREE_WIDTH> * leaf_tmp = new BPlusLeaf<BPlusTreeNodeData, BPlusTreeLeafData, TREE_WIDTH>();
		fprintf(stderr, "stored_leaf_id=%d\n", storage_leafs.DumpLeaf(leaf_tmp));
//		storage_leafs.GetLeafById<BPlusTreeNodeData, BPlusTreeLeafData, TREE_WIDTH>(-1);
		BPlusLeaf<BPlusTreeNodeData, BPlusTreeLeafData, TREE_WIDTH> * leaf_tmp1 = storage_leafs.GetLeafById<BPlusTreeNodeData, BPlusTreeLeafData, TREE_WIDTH>(-1);
		fprintf(stderr, "get_leaf_id = %lld\n", leaf_tmp1->id);
		delete leaf_tmp; delete leaf_tmp1;
/*		BPlusTree <INT_32, INT_32, 4ll> *tree = new BPlusTree<INT_32, INT_32, 4ll>(); 
		MAIL::Pair<INT_32, INT_32> tmp( 0 ,1 );
		fprintf(stdout, "%c\n", tree->Insert(tmp) ? '.':'!');
		fprintf(stdout, "%c\n", tree->Insert(tmp) ? '.':'!');
		fprintf(stdout, "%s\n", tree->Remove(tmp.key) ? "deleted" : "not deleted");
		fprintf(stdout, "%s\n", tree->Remove(tmp.key) ? "deleted" : "not deleted");
		fprintf(stderr, "%s , size=%lld\n", tree->isEmpty() ? "empty" : "non_empty", tree->size());
*/
		fprintf(stdout, "OK\n" );
//		delete tree;// delete  t1; delete t2;

/*		BPlusTreeNodeWordHash *n1 = new BPlusTreeNodeWordHash(1,2,3);
		BPlusTreeNodeWordHash *n2 = new BPlusTreeNodeWordHash(4,5,6);
		BPlusTreeNodeWordHash *n3 = new BPlusTreeNodeWordHash(7,8,9);
		fprintf(stderr, "TESTING BPlusNodesStorage...\n");
		storage_nodes.DumpNode(n1);
		storage_nodes.DumpNode(n2);
		storage_nodes.DumpNode(n3);
		fprintf(stderr, "n1_id=%lld, n2_id=%lld, n3_id=%lld\n ", n1->node_id, n2->node_id, n3->node_id);
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(0)->node_id, storage_nodes.GetNodeById(0)->word_hash, storage_nodes.GetNodeById(0)->chunk_number, storage_nodes.GetNodeById(0)->size );
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(1)->node_id, storage_nodes.GetNodeById(1)->word_hash, storage_nodes.GetNodeById(1)->chunk_number, storage_nodes.GetNodeById(1)->size );
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(2)->node_id, storage_nodes.GetNodeById(2)->word_hash, storage_nodes.GetNodeById(2)->chunk_number, storage_nodes.GetNodeById(2)->size );
		storage_nodes.DeleteNode(1);
		BPlusTreeNodeWordHash *n4 = new BPlusTreeNodeWordHash(10,11,12);
		storage_nodes.DumpNode(n4);
		fprintf(stderr, "new added node id=%lld\n", n4->node_id);
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(0)->node_id, storage_nodes.GetNodeById(0)->word_hash, storage_nodes.GetNodeById(0)->chunk_number, storage_nodes.GetNodeById(0)->size );
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(1)->node_id, storage_nodes.GetNodeById(1)->word_hash, storage_nodes.GetNodeById(1)->chunk_number, storage_nodes.GetNodeById(1)->size );
		fprintf(stderr, "restored nodes with ids : %lld=(%lld,%lld,%lld)\n", storage_nodes.GetNodeById(2)->node_id, storage_nodes.GetNodeById(2)->word_hash, storage_nodes.GetNodeById(2)->chunk_number, storage_nodes.GetNodeById(2)->size );

		for (INT_32 i = 0; i < TEST_SIZE; ++i){
			BPlusTreeNodeWordHash *n = new BPlusTreeNodeWordHash(i + 1, i + 2, i + 3);
			storage_nodes.DumpNode(n);
			fprintf(stderr, "added node id=%lld\n", n->node_id);
			delete n;
		}
		for (INT_32 i = 0; i < TEST_SIZE; ++i){
			BPlusTreeNodeWordHash *n = storage_nodes.GetNodeById(i);
			fprintf(stderr, "added node id=%lldi, node=(%lld,%lld,%lld)\n", n->node_id, n->word_hash, n->chunk_number, n->size);
			delete n;
		}
		for (INT_32 i = 0; i < TEST_SIZE; ++i){
			storage_nodes.DeleteNode(i);
			fprintf(stderr, "deleted %d node\n", i);
		}
		fprintf(stderr, "...OK\n");
		fprintf(stderr, "TESTING BPlusLeafStorage...\n");
		BPlusTreeLeaf *l1 = new BPlusTreeLeaf(5 , "test1");
		BPlusTreeLeaf *l2 = new BPlusTreeLeaf(8 , "loltest2");
		BPlusTreeLeaf *l3 = new BPlusTreeLeaf(11 , "lolloltest3");
		BPlusTreeLeaf *l4 = new BPlusTreeLeaf(14, "test4lollollol");
		fprintf(stderr, "storaged_leaf_id=%d\n",storage_leafs.DumpLeaf(l1));
		fprintf(stderr, "storaged_leaf_id=%d\n",storage_leafs.DumpLeaf(l2));
		fprintf(stderr, "storaged_leaf_id=%d\n",storage_leafs.DumpLeaf(l3));
		storage_leafs.DeleteLeaf(1);
		fprintf(stderr, "storaged_leaf_id=%d\n",storage_leafs.DumpLeaf(l4));
		for (INT_32 i = 0; i < 3; ++i){

			fprintf(stderr, "i=%d, lead=(%lld,%lld,%s)", i, storage_leafs.GetLeafById(i)->leaf_id, storage_leafs.GetLeafById(i)->data_size, storage_leafs.GetLeafById(i)->data);
		}
		for (INT_32 i = 0; i < TEST_SIZE ; ++i){
			CHAR_8 buf[500];
			sprintf(buf, "%d", i);
			BPlusTreeLeaf *l = new BPlusTreeLeaf(500, buf );
			fprintf(stderr, "dumped leaf with id=%d (%lld, %lld, %s)\n ",storage_leafs.DumpLeaf(l), l->leaf_id, l->data_size, l->data);
			delete l;
		}
		for (INT_32 i = 0; i < TEST_SIZE ; ++i){
			BPlusTreeLeaf *l = storage_leafs.GetLeafById(i);
			fprintf(stderr, "dumped leaf with id=%d (%lld, %lld, %s)\n ", i , l->leaf_id, l->data_size, l->data);
			delete l;
		}
		for (INT_32 i = 0; i < TEST_SIZE ; ++i){
			storage_leafs.DeleteLeaf(i);
			fprintf(stderr, "deleted leaf with id=%d\n", i);
		}
		fprintf(stderr, "...OK\n");
		delete n1; delete n2; delete n3; delete l1; delete l2; delete l3; delete l4;*/
	} catch (LogicException &e){
		fprintf(stderr, "Logic trouble %s\n", e.what());
		return EX_SOFTWARE;
	} catch (UnixException &e){
		fprintf(stderr, "Unix trouble %s err : %s\n", e.what(), strerror(e.code()));
		return EX_SOFTWARE;
	} catch (...) {
		fprintf(stderr, "houston we have a problem ;-(\n");
		return EX_SOFTWARE;
	}
	return EX_OK;
}
